package com.southminority.ethnic.service.user.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.southminority.ethnic.common.context.UserContext;
import com.southminority.ethnic.enums.RedisKeyEnum;
import com.southminority.ethnic.pojo.User;
import com.southminority.ethnic.service.email.EmailService;
import com.southminority.ethnic.service.redis.RedisService;
import com.southminority.ethnic.service.user.UserService;
import com.southminority.ethnic.mapper.user.UserMapper;
import com.southminority.ethnic.until.AesUtil;
import com.southminority.ethnic.until.JsonUtil;
import com.southminority.ethnic.until.NumberUntil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;

/**
* @author ASHTR
* @description 针对表【user(用户表)】的数据库操作Service实现
* @createDate 2025-08-29 13:46:29
*/
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
    implements UserService{

    @Autowired
    RedisService redisService;

    @Autowired
    EmailService emailService;

    @Override
    public Boolean getYzm(String email) {
        //查看是否有发送过验证码，假如有则判断验证码是否超过一分钟
        Long time= redisService.redisGetExpireTime(RedisKeyEnum.CAPTCHA_REGISTER.getKeyPrefix() + email,RedisKeyEnum.CAPTCHA_REGISTER.getTimeUnit());
        if (time+1>=RedisKeyEnum.CAPTCHA_REGISTER.getExpireTime()){//一分钟重新获取
            throw new RuntimeException("请勿频繁获取验证码");
        }
        String code= NumberUntil.getYZM6();
        redisService.redisSetValue(
                RedisKeyEnum.CAPTCHA_REGISTER.getKeyPrefix() + email,
                code,
                RedisKeyEnum.CAPTCHA_REGISTER.getExpireTime(),
                RedisKeyEnum.CAPTCHA_REGISTER.getTimeUnit()
                );
        emailService.sendSimpleMail(email,"注册验证码",code);
        return true;
    }

    @Override
    public Boolean logon(String email, String password, String passwordAgain, String username, String code) {
        if (!password.equals(passwordAgain)) {
            throw new RuntimeException("两次密码不一致");
        }

        String redisCode =(String) redisService.redisGetValue(RedisKeyEnum.CAPTCHA_REGISTER.getKeyPrefix() + email);
        if (redisCode == null) {
            throw new RuntimeException("验证码已经失效，请重新获取");
        }else if (!redisCode.equals(code)) {
            throw new RuntimeException("验证码错误");
        }

        //验证是否有该用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email)
                .or()
                .eq(User::getUsername, username);
        if (baseMapper.selectCount(wrapper) > 0) {
            throw new RuntimeException("该用户名或者邮箱已经被注册过了");
        }
        //删除验证码
        redisService.redisDelete(RedisKeyEnum.CAPTCHA_REGISTER.getKeyPrefix() + email);

        try {
            password= AesUtil.encryptStrAES(password);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        User user = new User();
        user.setEmail(email);
        user.setPassword(password);
        user.setUsername(username);
        return baseMapper.insert(user) > 0;
    }

    @Override
    public User login(String email, String password) {
        try {
            password= AesUtil.encryptStrAES(password);
            log.error("邮箱："+email+"\n密码："+password);
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getEmail, email)
                    .eq(User::getPassword, password);
            User user = baseMapper.selectOne(wrapper);

            if (user == null) {
                throw new RuntimeException("用户名或密码错误");
            }

            // JSON转User对象
            //User user = JsonUtil.fromJson(json, User.class);

            //删除旧token
            redisService.redisDelete(RedisKeyEnum.USER_TOKEN.getKeyPrefix()+user.getToken());

            //存token
            String token=NumberUntil.getUUID();
            user.setToken(token);
            if (baseMapper.updateById(user) == 0) {
                throw new RuntimeException("登录更新token出错");
            }
            user.setPassword(null);
            String jsonUser= JsonUtil.toJson(user);
            if(!redisService.redisSetValue(
                    RedisKeyEnum.USER_TOKEN.getKeyPrefix()+token,
                    jsonUser,
                    RedisKeyEnum.USER_TOKEN.getExpireTime(),
                    RedisKeyEnum.USER_TOKEN.getTimeUnit()
                    )){
                throw new RuntimeException("redis更新失败");
            }
            return user;
        } catch (JsonProcessingException e) {
            throw new RuntimeException("json格式转化出错\n"+e);
        } catch (IllegalBlockSizeException e) {
            throw new RuntimeException(e);
        } catch (BadPaddingException e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    public Boolean forgetYZM(String email) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email);
        if (baseMapper.selectCount(wrapper) == 0) {
            throw new RuntimeException("无该用户，请先注册");
        }
        //查看是否有发送过验证码，假如有则判断验证码是否超过一分钟
        Long time= redisService.redisGetExpireTime(RedisKeyEnum.CAPTCHA_FORGET.getKeyPrefix() + email,RedisKeyEnum.CAPTCHA_REGISTER.getTimeUnit());
        if (time+1>=RedisKeyEnum.CAPTCHA_FORGET.getExpireTime()){//一分钟重新获取
            throw new RuntimeException("请勿频繁获取验证码");
        }
        String code= NumberUntil.getYZM6();
        redisService.redisSetValue(
                RedisKeyEnum.CAPTCHA_FORGET.getKeyPrefix() + email,
                code,
                RedisKeyEnum.CAPTCHA_FORGET.getExpireTime(),
                RedisKeyEnum.CAPTCHA_FORGET.getTimeUnit()
        );
        emailService.sendSimpleMail(email,"忘记密码验证码",code);
        return true;
    }

    @Override
    public Boolean forget(String email, String password, String code) {
        String redisCode =(String) redisService.redisGetValue(RedisKeyEnum.CAPTCHA_FORGET.getKeyPrefix() + email);
        if (redisCode == null) {
            throw new RuntimeException("验证码已经失效，请重新获取");
        }else if (!redisCode.equals(code)) {
            throw new RuntimeException("验证码错误");
        }
        //密码加密
        try {
            password= AesUtil.encryptStrAES(password);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

        //验证是否有该用户
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(User::getEmail, email);
        User user = baseMapper.selectOne(wrapper);
        if (user==null) {
            throw new RuntimeException("无该用户，请先注册");
        }
        //删除旧token
        redisService.redisDelete(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + user.getToken());

        user.setPassword(password);
        return baseMapper.updateById(user) > 0;
    }

    @Override
    public Boolean updatePasswordFromOldPassword(String oldPassword, String newPassword) {
        try {
            oldPassword= AesUtil.encryptStrAES(oldPassword);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        try {
            newPassword= AesUtil.encryptStrAES(newPassword);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        //获取用户id
        Long userId = UserContext.getCurrentUserId();
        User user = baseMapper.selectById(userId);
        if (user==null) {
            throw new RuntimeException("无该用户，请先注册");
        }
        if (!user.getPassword().equals(oldPassword)){
            throw new RuntimeException("旧密码错误");
        }
        user.setPassword(newPassword);
        return baseMapper.updateById(user) > 0;
    }

    @Override
    public Boolean logout(String token) {
        String jsonUser= (String) redisService.redisGetValue(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token);
        if (jsonUser==null){
            throw new RuntimeException("token失效");
        }
        return redisService.redisDelete(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token);
    }


    //获取用户信息
    private static Integer tokenRemainTime;
    @Value("${self.redis.token-remain-life-cycle}")
    public void setTokenRemainTime(Integer tokenRemainTime) {
        UserServiceImpl.tokenRemainTime = tokenRemainTime;
    }

    @Override
    public String checkToken(String token) {
        Long time= redisService.redisGetExpireTime(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token,RedisKeyEnum.USER_TOKEN.getTimeUnit());
        if (time==-2){
            throw new RuntimeException("token失效");
        }if(time>=0&&time<=tokenRemainTime){
            LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(User::getToken, token);
            User user = baseMapper.selectOne(wrapper);
            if (user==null){
                throw new RuntimeException("用户信息有误");
            }
            //更新token
            String oldToken=token;
            token=NumberUntil.getUUID();
            redisService.redisSetValue(
                    RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token,
                    (String) redisService.redisGetValue(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token),
                    RedisKeyEnum.USER_TOKEN.getExpireTime(),
                    RedisKeyEnum.USER_TOKEN.getTimeUnit()
            );
            user.setToken(token);
            if (baseMapper.updateById(user)==0){
                throw new RuntimeException("更新token失败");
            }
            redisService.redisDelete(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + oldToken);
            return token;
        }else {
            return (String) redisService.redisGetValue(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token);
        }
    }

    @Override
    public User getUserByToken(String token) {
            try {
                String jsonUser= (String) redisService.redisGetValue(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token);
                if (jsonUser==null){
                    throw new RuntimeException("token失效");
                }
                return JsonUtil.fromJson(jsonUser,User.class);
            } catch (JsonProcessingException e) {
                throw new RuntimeException("用户redis信息解析失败\n"+e);
            }
    }

    @Override
    public Page<User> getUserPage(Integer pageNum, Integer pageSize, String keyword, Integer userType) {
        Page<User> page = new Page<>(pageNum, pageSize);

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(User.class, info -> !info.getProperty().equals("password")); // 排除password字段
        
        // 只有当userType不为null时才添加过滤条件
        if (userType != null) {
            wrapper.eq(User::getUserType, userType);
        }
        
        if (keyword != null && !keyword.isEmpty()) {
            wrapper.and(qw -> qw.like(User::getUsername, keyword)
                    .or()
                    .like(User::getEmail, keyword)
                    .or()
                    .like(User::getPhone, keyword));
        }

        return baseMapper.selectPage(page, wrapper);
    }

    @Override
    public Boolean updateUser(Long id, Integer newUserType) {
        User user = baseMapper.selectById(id);
        if (user==null){
            throw new RuntimeException("无该用户");
        }
        user.setUserType(newUserType);
        //更改token中记录的权限
        String token=user.getToken();
        String Json=(String) redisService.redisGetValue(RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token);
        if (Json!=null){
            try {
                User user1= JsonUtil.fromJson(Json,User.class);
                user1.setUserType(newUserType);
                redisService.redisSetValue(
                        RedisKeyEnum.USER_TOKEN.getKeyPrefix() + token,
                        JsonUtil.toJson(user1),
                        RedisKeyEnum.USER_TOKEN.getExpireTime(),
                        RedisKeyEnum.USER_TOKEN.getTimeUnit()
                );

            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }
        return baseMapper.updateById(user) > 0;
    }

    @Override
    public Boolean initPassword(Long id) {
        User user = baseMapper.selectById(id);
        if (user==null){
            throw new RuntimeException("无该用户");
        }
        //密码加密
        try {
            user.setPassword(AesUtil.encryptStrAES("123456"));
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }
        return baseMapper.updateById(user) > 0;
    }
}




